<template>
  <view class="chat-container" :style="pageHeight">
		<up-navbar :title="group.group_name" @leftClick="back" rightIcon="more-dot-fill" placeholder @rightClick="rightClick"></up-navbar>
		<h-watermark :title="imInfo?.username" :mobile="imInfo?.phone.slice(-4)" :titleSize="14" :mobileSize="14" :column="6"></h-watermark>
		<!-- 聊天窗口 -->
		<z-paging
			ref="paging"
			v-model="talkList"
			use-chat-record-mode
			safe-area-inset-bottom
			auto-to-bottom-when-chat
			auto-show-system-loading
			bottom-bg-color="#f8f8f8"
			:paging-style="{paddingTop: chatBoxHeight}"
			@query="queryList"
			@keyboardHeightChange="keyboardHeightChange"
			@hidedKeyboard="hidedKeyboard"
		>
			<view class="talk-list">
				<!-- 循环开始 -->
				<view v-for="(item, index) in talkList" :key="item.id" style="position: relative;">
					<view v-if="item.relation_type != 'repeat' && item.relation_type != 'received'">
						<!-- 聚合消息 -->
						<view v-if="isRepeatMsg(item)">
							<aggregate-message :message="item" :userInfo="userInfo" :imInfo="imInfo" :continuous="lastMsgRelationId == item.id"></aggregate-message>
						</view>

						<view v-else style="transform: scaleY(-1);">
							<!-- 时间戳 -->
							<view style="text-align: center">
								<view class="timestamp" v-if="showTimestamp(index)">
									{{setTimestamp(index)}}
								</view>
							</view>
							<view class="revoke" v-if="item.status == 12">
								<text v-if="item.from_account == imInfo.account">你撤回了一条消息<text v-if="item.content[0].type == 'text'" @click="handleReedit(item)" class="reEdit">重新编辑</text></text>
								<text v-else>{{item.username}}撤回了一条消息</text>
							</view>
							<view class="revoke" v-else-if="item.username == '系统提示'">
								<text>{{item.content[0].content}} [ {{item.send_time}} ]</text>
							</view>
							<view v-else class="item flex-col" :class="item.from_account != imInfo.account ? 'pull' : 'push'">
								<!-- 头像 -->
								<view @longpress="avatarLongpress(item, item.from_account != imInfo.account)" @touchstart="touchStart" @touchmove="touchMove" style="width: 72rpx; height: 72rpx;" @click="jumpPerson(item)">
									<up-image :src="setUserImg(item.from_phone)" width="72rpx" height="72rpx" radius="10rpx">
										<template #error>
											<view style="width: 100%; height: 100%;">
												<text class="pic-text">{{showUserName(item.username)}}</text>
											</view>
										</template>
									</up-image>
								</view>
								<!-- 名称 -->
								<view>
									<view class="chat-name" :style="{
										textAlign: item.from_account != imInfo.account ? 'left' : 'right',
										margin: item.from_account != imInfo.account ? '0 0 8rpx 14rpx' : '0 14rpx 8rpx 0',
									}">
										<text v-show="item.from_account == imInfo.account" style="font-size: 12px; margin-right: 6px;">{{formatTime(item.send_time)}} [{{item.msg_id}}]</text>
										{{ item.username }}
										<text v-show="item.from_account != imInfo.account" style="font-size: 12px; margin-left: 6px;">{{formatTime(item.send_time)}} [{{item.msg_id}}]</text>
									</view>
									<!-- 聊天气泡框 -->
									<view class="msg-container">
										<view class="inner" :id="`msg-${item.id}`">
											<view @longpress="(e) => longpress(e, item)" @touchstart="touchStart" @touchmove="touchMove">
												<view class="reply-msg" @click="replyMsgClick(item?.replyMsg)" v-if="item?.relation_type && item?.relation_type == 'reply'">
													<view class="reply-name">{{item?.replyMsg?.from_username}}：</view>
													<up-parse :content="item.replyMsg?.html"></up-parse>
												</view>
												<view v-for="item2 in item.content">
													<view v-if="item2.content !== ''" class="content">
														<message :groupId="group.group_id" :message="item" :detail="item2" :type="item2.type"></message>

														<view v-show="item.success && item.success == 'loading'" class="send-loading">
															<up-loading-icon :size="14" v-if="item.success == 'loading'"></up-loading-icon>
															<up-icon v-if="item.success == 'error'" name="error-circle-fill" color="red" :size="14"></up-icon>
														</view>
													</view>
												</view>
												<!-- 收到 -->
												<view class="related" v-show="isMentioned(item) || (item.listRelated && item.listRelated.length > 0)">
													<view v-if="item.listRelated && item.listRelated.length > 0" class="related-member">
														👌<span v-for="(related, relatedIndex) in item.listRelated" :key="related.id">{{related.username}}<b v-if="relatedIndex < item.listRelated.length-1">,</b></span>
													</view>
													<view class="related-btn" v-show="isMentioned(item)">
														<up-button  @click="onRelated(item)" :customStyle="{width: '120rpx', margin: '0 12rpx 0 6px'}" size="small" :hairline="false" shape="circle" text="👌收到"></up-button>
														<up-button @click="onReply(item)" :customStyle="{width: '120rpx', margin: '0 12rpx 0 6px'}" size="small" :hairline="false" shape="circle" text="回复"></up-button>
													</view>
												</view>
											</view>
										</view>
									</view>
									<!-- 聊天气泡框结束 -->
									<!-- 已读未读 -->
									<view class="readStatus">
										<view style="text-align: right;" v-if="item.from_account == imInfo.account && item.have_read_num < item.need_read_num">
											<text @click="unReadView(item)">{{setReadNum(item.need_read_num, item.have_read_num)}}人未读</text>
										</view>
										<view style="text-align: right;" v-if="item.from_account == imInfo.account && item.have_read_num >= item.need_read_num">
											<text @click="unReadView(item)">全部已读</text>
										</view>
									</view>
								</view>
							</view>
						</view>
					</view>

				</view>
				<!-- 循环结束 -->
			</view>
			<!-- 底部聊天输入框 -->
			<template #bottom>
				<chat-input-bar ref="inputBar" :isGroup="true" :groupId="v" @send="handleSendClick" @handleMention="handleMention" @chooseImage="chooseImage" @chooseCamera="chooseCamera" @chooseFile="chooseFile" @copyShow="handleCopyShow" />
			</template>
		</z-paging>
		
		<up-popup closeable :customStyle="{width: '100vw', height: 'auto'}" :show="unReadShow" mode="bottom"  @close="unReadShow = false">
			<view>
				<view style="text-align: center; margin-top: 12px; font-size: 16px; font-weight: 500;">消息接收人列表</view>
				<view style="display: flex; justify-content: center;">
					<up-tabs @change="tabChange" lineColor="#666" :list="[{name: no_read.length > 0 ? `未读 (${no_read.length})` : '未读'},{name: have_read.length > 0 ? `已读 (${have_read.length})` : '已读'}]" :activeStyle="{color: '#111', fontWeight: 500}" :itemStyle="{width: '100px', height: '42px'}"></up-tabs>
				</view>
				<view style="background-color: #F2F1F6; border-top: 1px solid #ddd; margin-top: -3px;">
					<up-list height="400">
						<view v-if="msgTakeList.length == 0" style="display: flex; flex-direction: column; align-items: center; padding-top: 44px;">
							<image style="width: 150px; height: 150px;" mode="aspectFit" src="/static/chat/nomsg.png"></image>
							<view style="margin-top: 8px; color: #555;">
								{{readTabs == 0 ? '全部成员已读' : '全部成员未读'}}
							</view>
						</view>
						<up-list-item v-for="(item, index) in msgTakeList" :key="index">
							<view style="display: flex; align-items: center; width: 100%; padding: 6px 30px; background-color: #fff;">
								<view style="width: 34px; height:34px;">
									<up-image :src="setUserImg(item.phone)" width="34px" height="34px" radius="4px">
										<template #error>
											<view style="width: 100%; height: 100%;">
												<text
													:style="{
														display: 'flex',
														justifyContent: 'center',
														alignItems: 'center',
														width: '34px',
														height: '34px',
														borderRadius: '4px',
														color: '#fff',
														fontSize: '12px',
														backgroundColor: '#3D85FC'
													}"
												>{{showUserName(item.username)}}</text>
											</view>
										</template>
									</up-image>
								</view>
								<view style="margin-left: 16px;">
									<view>{{item.username}}</view>
									<view v-if="readTabs == 1" style="color: #999; font-size: 13px;">{{item.read_time}}</view>
								</view>
							</view>
						</up-list-item>
					</up-list>
				</view>
			</view>
		</up-popup>

		<up-popup @close="mentionClose" closeIconPos="top-left" :customStyle="{width: '100vw', height: '72vh', backgroundColor: '#F2F1F6'}" closeable :show="mentionShow" mode="bottom">
			<view class="mention-header">
				<view>选择要@的人</view>
				<view v-show="atArr.length > 0" @click="sendAtMsg" style="position: absolute; top: 50%; transform: translateY(-25%); right: 20px;">确定</view>
			</view>
			<view style="padding: 16px 18px 18px 18px; background-color: #fff;">
				<up-search shape="square" @change="mentionSearchChange" :showAction="false" v-model="mentionSearch"></up-search>
			</view>
			<view class="mention-all">
				<view class="mention-list" @click="sendAtMsg('all')">
					<view style="width: 38px; height: 38px; margin-left: 28px;">
						<up-image :src="setUserImg(321123)" width="38px" height="38px" radius="4px">
							<template #error>
								<view style="width: 100%; height: 100%;">
									<text
										:style="{
											display: 'flex',
											justifyContent: 'center',
											alignItems: 'center',
											width: '38px',
											height: '38px',
											borderRadius: '4px',
											color: '#fff',
											fontSize: '12px',
											backgroundColor: '#3D85FC',
											fontSize: '18px',
											fontWeight: '500',
											lineHeight: '38px'
										}"
									>@</text>
								</view>
							</template>
						</up-image>
					</view>
					<view style="margin-left: 14px;">所有人</view>
				</view>
			</view>
			<view class="mention-member">
				<z-paging ref="mentionPaging" v-model="memberList" @query="getGroupMember" :fixed="false">
					<view v-for="(item, index) in memberList" :key="index">
						<view @click="selectMember(item)" style="display: flex; align-items: center; width: 100%; padding: 6px 18px; background-color: #fff;">
							<view>
								<up-checkbox :checked="attChecked(item)" @change="() => selectMember(item)" usedAlone></up-checkbox>
							</view>
							<view style="width: 38px; height:38px; margin-left: 4px;">
								<up-image :src="setUserImg(item.phone)" width="38px" height="38px" radius="4px">
									<template #error>
										<view style="width: 100%; height: 100%;">
											<text
												:style="{
													display: 'flex',
													justifyContent: 'center',
													alignItems: 'center',
													width: '38px',
													height: '38px',
													borderRadius: '4px',
													color: '#fff',
													fontSize: '12px',
													backgroundColor: '#3D85FC'
												}"
											>{{showUserName(item.username)}}</text>
										</view>
									</template>
								</up-image>
							</view>
							<view style="margin-left: 16px;">
								<view>{{item.username}}</view>
							</view>
						</view>
					</view>
				</z-paging>
			</view>
		</up-popup>

		<up-popup :customStyle="{width: 'auto', height: 'auto', padding: '0'}" :show="copyShow" mode="center" :closeOnClickOverlay="false">
			<view class="copyImgModal">
				<view>
					<view style="padding: 8px;">
						<image v-if="copyContent === ':/image'" mode="widthFix" style="max-width: 250px;" :src="setCopyImg"></image>
						<view v-if="copyContent === ':/img/text'">
							<up-parse :content="copyStore.copyValue?.html"></up-parse>
						</view>
					</view>
					<view class="footer">
						<view style="border-right: 1px solid #ddd;">
							<up-button @click="copyCancel" :customStyle="{border: 'none'}" plain type="primary" text="取消"></up-button>
						</view>
						<view>
							<up-button @click="copySend" :customStyle="{border: 'none'}" plain type="primary" text="确定"></up-button>
						</view>
					</view>
				</view>
			</view>
		</up-popup>

		<xe-upload ref="XeUpload" :options="uploadOptions" @beforUpload="beforUpload" @callback="handleUploadCallback"></xe-upload>
		
		<PopoverMenu ref="popoverMenu" :imInfo="imInfo" :group="group" :currentMsg="currentMsg" :popStyle="popStyle" @handleReply="handleReply" @handleRevoke="handleRevoke"></PopoverMenu>

  </view>
</template>

<script>
import { chatApi } from '@/apis/cloud/chat'
import { useChatStore, useGroupStore, useSocketStore, useUserStore, useCopyStore } from '@/pinia-store/user'
import { extractHrefOrReplace, getScaledImageSize, chooseFile, fileTypeFormat, formatFileSize, fixImageSrc, getTimeStringAutoShort, setIcon, processImageUrl, objectToFormData } from "@/utils/chat"
import { chooseFileAndroid } from '@/utils/filePicker.js';
import dayjs from "dayjs"
import { mapStores } from 'pinia'
import { random } from "@/uni_modules/uview-plus"
import graceRichText from "../config/rich-text-format.js"
import ChatInputBar from "../components/chat-input-bar.vue"
import AggregateMessage from "../components/AggregateMessage.vue"
import Message from '@/pages/chat/message/components/Message.vue'
import ChatMixins from '../config/ChatMixins.js';
import PopoverMenu from '../components/PopoverMenu.vue';

export default {
	mixins: [ChatMixins],
  components: {
		ChatInputBar,
		AggregateMessage,
		Message,
		PopoverMenu
	},
  data () {
    return {
			uploadOptions: {},
			num: 1,
			safeAreaHeight: 0,
			talkList: [],// 聊天列表数据
			group: {},
			imInfo: {},
			userInfo: {},
			index: 0,
			page: 1,
			dialogId: null,
			unReadShow: false,
			have_read: [],
			no_read: [],
			msgTakeList: [],
			readTabs: 0,
			focus: false,
			copyShow: false,
			mentionShow: false,
			memberList: [],
			atArr: [],// @列表
			content: '',// 发送内容
			recall: 0,
			copyContent: '',
      chatBoxHeight: 0,
			mentionSearch: '',
			mentionTimer: null,
			previousMsg: []
		}
	},
	computed: {
		...mapStores(useGroupStore, useChatStore, useUserStore, useSocketStore, useCopyStore),
		lastMsg () {
			return this.socketStore.lastMsg;
		},
		// 页面高度
		pageHeight () {
			// #ifdef H5
			if(this.safeAreaHeight > 0){
				return `height: calc(${this.safeAreaHeight}px - var(--window-top));`
			}
			return "";
			// #endif
			// #ifdef APP-PLUS
			return "";
			// #endif
		},
		setCopyImg() {
			return this.copyStore.copyValue.replace(':81', '');
		},
		lastMsgRelationId(){
			return [...this.talkList].pop().relation_id;
		}
  },
	created() {
		const _self = this;
		this.safeAreaHeight = uni.getSystemInfoSync().safeArea.height;
		// #ifdef H5
    this.chatBoxHeight = '45px';
		// 初始化WS
		uni.getStorage({
			key: '_ws',
			success: function (res) {
				_self.socketStore.init(JSON.parse(res.data));
			}
		});
		this.group = JSON.parse(uni.getStorageSync('groupMsg'));// 当前群组信息
		this.imInfo = JSON.parse(uni.getStorageSync('imInfo'));// 当前登录用户
		this.userInfo = JSON.parse(uni.getStorageSync('user')).user;
		this.dialogId = uni.getStorageSync('nowDialogId');
		// #endif

		// #ifdef APP-PLUS
		this.chatBoxHeight = '70px';
		this.group = this.groupStore.group;// 当前群组信息
		this.imInfo = this.chatStore.imInfo;// 当前登录用户
		this.userInfo = this.userStore.user;
		this.dialogId = this.socketStore.nowDialogId;
		// #endif

		uni.$on('setGroupHaveRead', (data) => {
			this.setGroupMsgRead(data);
		})

		uni.$on('setGroupRecallMessage', (data) => {
			this.setRecall(data);
		})

		uni.$on('setRecallMessage', (data) => {
			this.setRecall(data);
		})

		uni.$on('updaterReceived', (data) => {
			this.updaterReceived(data);
		})

		uni.$on('updateRelations', (data) => {
			this.updateRelations(data);
		})

		this.getUnreadChatRecord();
		this.uploadOptions.url = `https://chat.mfarmers.com:88/phpApi/public/index.php/users/Index/uploadImg.html?account=${this.imInfo.account}&to_account=${this.group.group_id}&department=${this.imInfo.department}`
	},
	watch: {
		lastMsg: async function (newVal, oldVal) {
			const data = newVal.data;
			if (this.group.group_id === newVal.groupId) {
				// 对图片 文件单独处理
				if(data.from.content2[0].type == 'img') {
					data.from.content2[0].html = await this.setImgUrl(data.from.content2[0].content);
				}
				if(data.from.content2[0].type == 'img/text') {
					data.from.content2[0].html = await this.setHtmlContent(data.from.content2[0].content);
				}

				if(newVal.relation_type && newVal.relation_type == 'reply') {
					const replyMsg = await chatApi(this.userInfo.token, {
					  'data[groupId]': this.group.group_id,
					  'data[id]': newVal.relation_id,
					  'data[token]': this.userInfo.token,
					  url: 'index.php/users/message/group-chat'
					})

					if(replyMsg.data) {
						replyMsg.data.content = JSON.parse(replyMsg.data.content);
						let { content, status, from_username } = replyMsg.data
						newVal.replyMsg = replyMsg.data;
						newVal.replyMsg.html = '';
						content.forEach(async(i) => {
							if(i.content != '') {
								newVal.replyMsg.html += await this.getQuoteContext(i, status, from_username);
							}
						});
					}
				}
				let lastMsg = {
					type: data.from.content2[0].type,
					content: data.from.content2,
					send_time: data.from.send_time,
					msg_id: newVal.msg_id,
					status: 10,
					id: newVal.id,
					avatar: data.from.avatar,
					username: data.from.username,
					need_read_id: newVal.need_read_id,
					need_read_num: newVal.need_read_num,
					from_phone: data.from.from_phone,
					from_account: data.from.account,
					replyMsg: newVal.replyMsg,
					relation_type: newVal.relation_type,
					success: 'success',
					to_account_str: newVal.to_account_str
				};

				if(data.fromType == 4 && data.from_phone == '000000') {
					lastMsg.username = '系统提示';
				}

				this.$refs.paging.addChatRecordData(lastMsg);

				// 群聊已读参数
				newVal.index = this.talkList.length - 1;
				newVal.from_account = lastMsg.from_account;
				// 设置接收信息已读
				this.setHaveRead(newVal);
      }
    }
  },
	methods: {
		isRepeatMsg(args) {
			let { relation_type = 'none', relation_id = 0 } = args
			return relation_type=='related' && !!(relation_id & 0b1000)
		},
		replyMsgClick(replyMsg) {
			if(replyMsg.content && replyMsg.content[0]?.type == 'file') {
				this.openDoc(replyMsg, replyMsg.content[0], this.userInfo.worker_id)
			}
		},
		isMentioned(item) {
			let accounts = (item.to_account_str ? item.to_account_str : '').split(',')
			return (accounts.includes(this.imInfo.account) || accounts.includes('all')) && this.imInfo.account != item.from_account
		},
		updateRelations(data) {
			let message =	this.talkList.find((i) => i.id == data.id);
			if(message) {
				message.relation_type = data.relation_type
				message.relation_id = data.relation_id
			}
		},
		updaterReceived(data) {
			this.talkList.some(item => {
				if(item.id == data.id) {
					item.listRelated = data.received_list;
				}
			})
		},
		async onRelated(item) {
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[gid]': this.group.group_id,
				'data[mid]': item.id,
				url: 'index.php/users/message/received'
			}
			const msg = await chatApi(this.userInfo.token, params);
		},
		onReply(item) {
			this.currentMsg = item;
			this.avatarLongpress(item, item.from_phone != this.imInfo.phone , true);
			this.$refs.inputBar.setReplyContent(item);
		},
		// 获取历史消息
		async queryList(pageNo, pageSize) {
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				'data[groupId]': this.group.group_id,
				'data[myPhone]': this.imInfo.phone,
				'data[phone]': this.imInfo.phone,
				'data[page]': pageNo,
				'data[pageSize]': 30,
				url: 'index.php/users/Group/getGroupChatRecord'
			}

			const msg = await chatApi(this.userInfo.token, params);

			if (msg.code == 200) {
				if(msg.data && msg.data.length == 0) {
					uni.showToast({
						icon: 'none',
						title: '没有更多消息了'
					})
					this.$refs.paging.complete([]);
					return
				}

				const cache = await Promise.all(msg.data.map(async(item) => {
					// 查询收到信息
					if(item.related & 0b10) {
						const replyMsg = await chatApi(this.userInfo.token, {
							'data[relationType]': 'received',
							'data[mid]': item.id,
							'data[token]': this.userInfo.token,
							url: 'index.php/users/message/listRelatedMsg'
						})
						item.listRelated = replyMsg.data;
					}

					// 是否有引用信息
					if(item.relation_type && item.relation_type == 'reply') {
						const replyMsg = await chatApi(this.userInfo.token, {
							'data[groupId]': this.group.group_id,
							'data[id]': item.relation_id,
							'data[token]': this.userInfo.token,
							url: 'index.php/users/message/group-chat'
						})

						if(replyMsg.data) {
							replyMsg.data.content = JSON.parse(replyMsg.data.content);
							let { content, status, from_username } = replyMsg.data
							item.replyMsg = replyMsg.data;
							item.replyMsg.html = '';
							content.forEach(async(i) => {
								if(i.content != '') {
									item.replyMsg.html += await this.getQuoteContext(i, status, from_username);
								}
							});
						}
					}
					item.content = this.checkContent(item.content);
					item.need_read_id = item.need_read_id ? item.need_read_id : '';
					item.have_read_id = item.have_read_id ? item.have_read_id : '';
					for (const content of item.content) {
						if (content.type === 'img') {
							content.html = await this.setImgUrl(content.content);
						}
						if (content.type === 'img/text') {
							content.html = await this.setHtmlContent(content.content);
						}

						if (content.type === 'apply') {
							try {
								// 把 apply 的 content 再解析一次
								content.applyData = JSON.parse(content.content);
								// 生成一个简单的 html 或展示文本，也可以直接渲染 applyData
								content.html = `
									<div class="apply-msg">
										<div class="apply-title">${content.applyData.title}</div>
										<div class="apply-status">状态：${content.applyData.status === 1 ? '已同意' : '待处理'}</div>
										<ul>
											${content.applyData.detail.map(d => `<li>${d.label}: ${d.value}</li>`).join('')}
										</ul>
									</div>
								`;
							} catch (e) {
								content.applyData = null;
								content.html = '审批单解析失败';
							}
						}
						if (content.type === 'apply_urge') {
							try {
								// 把 apply 的 content 再解析一次
								content.applyData = JSON.parse(content.content);
								// 生成一个简单的 html 或展示文本，也可以直接渲染 applyData
								content.html = `
									<div class="apply-msg">
										<div class="apply-title">${content.applyData.title}</div>
										<div class="apply-content">${content.applyData.content}</div>
									</div>
								`;
							} catch (e) {
								content.applyData = null;
								content.html = '审批单解析失败';
							}
						}

						if (content.type === 'apply_mention') {
							try {
								// 把 apply 的 content 再解析一次
								content.applyData = JSON.parse(content.content);
								// 生成一个简单的 html 或展示文本，也可以直接渲染 applyData
								content.html = `
									<div class="apply-msg">
										<div class="apply-title">${content.applyData.title}</div>
										<div class="apply-content">${content.applyData.content}</div>
									</div>
								`;
							} catch (e) {
								content.applyData = null;
								content.html = '审批单解析失败';
							}
						}

						if (content.type === 'log') {
							try {
								content.logData = JSON.parse(content.content);
								content.html = `
									<div class="log-msg">
										<div class="log-title">${content.logData.title}</div>
										<div class="log-content">${content.logData.content}</div>
									</div>
								`;
							} catch (e) {
								content.logData = null;
								content.html = '日志内容解析失败';
							}
						}
						// 新增 notice 类型数据解析
						if (content.type === 'notice') {
							try {
								content.noticeData = JSON.parse(content.content);
								content.html = `
									<div class="notice-msg">
										<div class="notice-tag">通知</div>
										<div class="notice-title">${content.noticeData.title}</div>
										<div class="notice-content">${content.noticeData.content}</div>
									</div>
								`;
							} catch (e) {
								content.noticeData = null;
								content.html = '通知内容解析失败';
							}
						}
					}
					return item
				}))
				cache.reverse();
				this.$refs.paging.complete(cache);
			}else {
				this.$refs.paging.complete(false);
			}
		},

		handleMention() {
			uni.hideKeyboard();
			this.mentionShow = true
		},
		avatarLongpress(user, type, manual) {
			// 只有在没有滑动的情况下才执行长按逻辑
			if (this.moved && !manual) return
			if(type) {
				const cursor = this.$refs.inputBar.cursor;
				const str = `@${user.username} `
				this.$refs.inputBar.atBlocks.push({ start: cursor+1, end: cursor+str.length, user: user})
				this.$refs.inputBar.cursor = +cursor + str.length;

				this.$refs.inputBar.msg += str;
			}
		},
		sendAtMsg(all) {
			const before = this.$refs.inputBar.msg.slice(0, this.$refs.inputBar.cursor)
			const after = this.$refs.inputBar.msg.slice(this.$refs.inputBar.cursor)

			let currentCursor = this.$refs.inputBar.cursor

			// 抽出函数：移动已存在块的位置
			const shiftBlocks = (pos, len) => {
				this.$refs.inputBar.atBlocks.forEach(block => {
					if (block.start >= pos) {
						block.start += len
						block.end += len
					}
				})
			}

			// 处理所有人
			if (all == 'all') {
				const insertText = '所有人 '
				const start = currentCursor
				const end = start + insertText.length

				this.$refs.inputBar.msg = before + insertText + after
				this.$refs.inputBar.oldContent += this.$refs.inputBar.msg
				this.$refs.inputBar.cursor = end
				this.mentionClose()

				shiftBlocks(start, insertText.length)
				this.$refs.inputBar.atBlocks.push({ start, end, user: { username: 'all' }} );
				return
			}

			// 普通 @ 用户插入（每个用户一个块）
			let newContent = before + after
			this.atArr.forEach((item, index) => {
				// 注意 index==0 不加 @
				const text = (index === 0 ? `${item.username} ` : `@${item.username} `)
				const start = currentCursor
				const end = start + text.length
				// 插入文本
				const beforePart = index === 0 ? '' : newContent.slice(0, start)
				const afterPart = newContent.slice(start)
				newContent = beforePart + text + afterPart
				// 更新已有块位置
				shiftBlocks(start, text.length)

				// 记录块
				this.$refs.inputBar.atBlocks.push({ start, end, user: item})

				currentCursor = end
			})
			this.$refs.inputBar.msg += newContent
			this.$refs.inputBar.oldContent = this.$refs.inputBar.msg
			this.$refs.inputBar.cursor = currentCursor

			this.mentionClose()
		},
		mentionClose() {
			this.atArr = [];
			this.mentionSearch = '';
			this.mentionShow = false;
		},
		attChecked(row) {
			if(this.atArr.findIndex(item => {return item.id == row.id}) == -1) {
				return false
			}else {
				return true
			}
		},
		selectMember(row) {
			const find = this.atArr.findIndex(item => item.id == row.id);
			if(find == -1) {
				this.atArr.push(row);
			}else {
				this.atArr.splice(find, 1);
			}
		},
		mentionSearchChange() {
			clearTimeout(this.mentionTimer);
			this.mentionTimer = setTimeout(() => {
				this.$refs.mentionPaging.reload();
			}, 200);
		},
		async getGroupMember(pageNo, pageSize) {
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[keywords]': this.mentionSearch,
				'data[pageSize]': 20,
				'data[page]': pageNo,
				'data[groupId]': this.group.group_id,
				url: 'index.php/users/Group/getGroupMember'
			}

			const msg = await chatApi(this.userInfo.token, params);

			if(msg.code == 200) {
				this.$refs.mentionPaging.complete(msg.data);
			}else {
				this.$refs.mentionPaging.complete(false);
			}
		},
		setReadNum(need_read_num, have_read_num) {
			return +need_read_num - +have_read_num
		},
		handleReply() {
			this.avatarLongpress(this.currentMsg, this.currentMsg.from_phone != this.imInfo.phone , true);
			this.$refs.inputBar.setReplyContent(this.currentMsg);
		},
		copySend() {
			if(this.$refs.inputBar.msg == '粘贴:/img') {
				let sendMsg = {
				  type: 'img',
				  content: [{
				    type: 'img',
				    content: this.copyStore.copyValue,
				    html: { url: this.copyStore.copyValue, width: 100, height: 100 },
				  }],
				  send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
				  status: 10,
				  id: random(10000, 999999),
				  fromavatar: this.imInfo.avatar,
				  fromname: this.imInfo.username,
				  from_phone: this.imInfo.phone,
				  from_account: this.imInfo.account,
				  uuid: Math.random().toString(36).substring(2, 14),
				}
				this.$refs.paging.addChatRecordData(sendMsg);
				this.sendMessage(this.copyStore.copyValue, 'img', null, sendMsg);
			}
		},
		async handleRevoke() {
			const current = new Date(this.currentMsg.send_time).getTime();
			const now = new Date().getTime();
			if((now-current) > (this.recall*1000)) {
				uni.showToast({
					icon:'none',
					title: '已超出撤回时间无法撤回',
					duration:1500
				})
				return
			}
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				'data[messageId]': this.currentMsg.id,
				url: 'index.php/users/message/group/recall'
			}

			const msg = await chatApi(this.userInfo.token, params);

			if(msg.code == 200) {
				const findIndex = this.talkList.findIndex(item => {
					return item.id == this.currentMsg.id
				})
				this.talkList[findIndex].status = 12;
			}
		},
		tabChange(e) {
			this.readTabs = e.index;
			if(e.index == 0) {
				this.msgTakeList = this.no_read;
			}else {
				this.msgTakeList = this.have_read;
			}
		},
		async unReadView(data) {
			this.unReadShow = true;
			// const str = data.id.split('-');
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[gcrid]': data.id,
				'data[groupId]': this.group.group_id,
				url: 'index.php/users/Group/getGroupChatReadDetail.html'
			}
			const msg = await chatApi(this.userInfo.token, params);
			if(msg.code == 200) {
				this.have_read = msg.have_read;
				this.no_read = msg.no_read;
				this.msgTakeList = msg.no_read;
			}
		},
		setGroupMsgRead(data) {
			this.$nextTick(() => {
				const findMsg = this.talkList.find(item => {
					return data.gcrid == item.id
				})
				

				if(findMsg?.have_read_num && findMsg?.have_read_num >= findMsg?.need_read_num) return;
				if(findMsg?.have_read_id && findMsg?.need_read_id.indexOf(`${data.uid}`) == -1) return;
				if(findMsg?.have_read_id && findMsg?.have_read_id.indexOf(`${data.uid}`) != -1) return;
				
				if(!findMsg?.have_read_id) {
					findMsg.have_read_id = '';
					findMsg.have_read_num = 0;
				}
				findMsg.have_read_id = findMsg.have_read_id + ',' + data.uid;
				findMsg.have_read_num++;
			})
		},
		async getUnreadChatRecord() {
			const params = {
				'data[page]': '1',
				'data[pageSize]': '999999',
				'data[userId]': this.imInfo.id,
				'data[groupId]': this.group.group_id,
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				url: 'index.php/users/Group/getUnreadChatRecord'
			}
			const msg = await chatApi(this.userInfo.token, params);
			const ids = [];
			if(msg.code == 200) {
				msg.data.forEach(item => {
					ids.push(item.id);
				})
			}
			if(ids.length > 0){
				this.setAllMsgRead(ids);
			}

		},
		async setAllMsgRead(ids) {
			const params = {
				data: {
					ids: ids,
					myAccount: this.imInfo.account,
					userId: this.imInfo.id,
					groupId: this.group.group_id,
				},
				url: 'index.php/users/Group/setHaveRead_3'
			}

			const msg = await chatApi(this.userInfo.token, objectToFormData(params))
		},
    // 设置已读
		async setHaveRead(record) {
			const params = {
				'data[account]': this.imInfo.account,
				'data[token]': this.userInfo.token,
				'data[myAccount]': this.imInfo.account,
				'data[id]': record.id,
				'data[groupId]': this.group.group_id,
				url: 'index.php/users/Group/setHaveRead'
			}

			const msg = await chatApi(this.userInfo.token, params);

			let haveRead = {
				uid: this.imInfo.id,// 用户id
				type: 'groupHaveRead',
				from: this.imInfo.account, // 来自谁
				to: record.from_account, // 接收者
				groupId: this.group.group_id, // 群组ID
				gcrid: record.id,
				chatCacheIndex: record.index, // 第几个
			};

			this.socketStore.send(haveRead);
		},
		splitMentionText(str) {
			const result = [];
			// 改进正则：匹配 单独的@ 或 @xxx（至少一个非空格）
			const regex = /(@{2,}[^\s]+|@[^\s]+|@)/g;

			let lastIndex = 0;
			let match;

			while ((match = regex.exec(str)) !== null) {
				const start = match.index;

				// 先加上前面的普通文字
				if (start > lastIndex) {
					result.push(str.slice(lastIndex, start));
				}

				const token = match[0];
				if (token.startsWith('@@')) {
					// 把第一个 @ 当普通字符，剩下部分再分割
					result.push('@');
					const remain = token.slice(1); // 去掉第一个 @
					result.push(remain);
				} else {
					result.push(token);
				}

				lastIndex = regex.lastIndex;
			}

			// 最后剩余普通文字
			if (lastIndex < str.length) {
				result.push(str.slice(lastIndex));
			}

			return result.filter(Boolean);
		},
		checkLastTwo(arr, value) {
		  if (!Array.isArray(arr)) return false;
		  if (arr.length < 2) return false; // 长度不足两位直接返回 false

		  const lastTwo = arr.slice(-2);
		  return lastTwo.every(item => item === value);
		},
    // 信息发送
		async sendMessage (value, contentType, fileInfo, fileMsg) {
			try {
				let content = null;
				if(contentType === 'text') {
					content = `<p>${this.linkify(value)}</p>`
				}else {
					content = value;
				}
				
				let atArr = [];
				let to_account_str = [];
				let groupType = 'group'

				if(contentType == 'text' && this.$refs.inputBar.atBlocks.length > 0) {
					groupType = 'morePerson';
					let str = '';
					const atResult = this.splitMentionText(this.$refs.inputBar.msg);
					atResult.forEach(item => {
						if(item.indexOf('@') !== -1) {
							const val = item.slice(1, item.length);
							if(val == '所有人') {
								str += '<span class="mceNonEditable unfocusable" data="all">@所有人</span>&nbsp;';
								atArr.push('all');
								to_account_str.push('all');
							}else {
								if(val == ' ') return
								const find = this.$refs.inputBar.atBlocks.find(memeber => val == memeber.user.username)
								if(find) {
									atArr.push(find.user.phone);
									to_account_str.push(find.user.account);
									str += 	`<span class="mceNonEditable unfocusable" data="${find.phone}">${item}</span>&nbsp;`
								}else {
									str += item;
								}
							}
						}else {
							str += item;
						}
					})

					content = `<p>${str}</p>`
				}

				this.$refs.inputBar.atBlocks = [];
				this.$refs.inputBar.oldContent = '';

				let fromType = 1;
				switch (groupType) {
					case 'group':
						fromType = 1;
						break;
					case 'all':
					case 'morePerson':
						fromType = 2;
						break;
					default:
						fromType = 3;
						break;
				};

				// 处理消息发送数据
				const sendData = {
					type: 'chatMessage',
					timestamp: new Date().getTime(),
					groupId: this.group.group_id,
					msgId: `${this.imInfo.account}_${new Date().getTime()}`,
					to_account_str: to_account_str.join(','), // 个人u99590286f04cc2864c0e 或 all
					relation_id: null,
					relation_type: 'none',
					data: {
						from: {
							fromType: fromType,
							send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
							account: this.imInfo.account,
							from_phone: this.imInfo.phone,
							username: this.imInfo.username,
							avatar: this.imInfo.avatar,
							content: content,
							content_text: value,
							content2: [{
								type: contentType,
								content: content
							}],
						},
						to: {
							groupId: this.group.group_id,
							type: 'group',
							groupType: groupType,
							atArr: atArr,
						}
					}
				}

				if(this.$refs.inputBar.reply) {
					sendData.relation_id = this.currentMsg.id;
					sendData.relation_type = 'reply';
				}
				// 文件信息单独处理
				if (contentType == 'file') {
					sendData.data.from.content2 = [{
						uploadCompletedNum: 1,
						needUploadNum: 1,
						percentComplete: 100,
						content: '文件',
						icon: setIcon(fileInfo.name),// 根据后缀处理
						name: fileInfo.name,
						url: content,
						type: 'file',
						fid: fileMsg.fid,
						formatSize: fileInfo.isCopy ? fileInfo.formatSize : formatFileSize(fileInfo.size),
						localpath: ''
					}]
				}

				if (contentType == 'file' || contentType == 'img') {
					delete sendData.data.from.content;
					delete sendData.data.from.content_text;
					sendData.data.from.content2[0].fid = fileMsg.fid
				}
				
				const params = {
					'data[account]': this.imInfo.account,
					'data[token]': this.userInfo.token,
					'data[status]': 10,
					'data[data]': JSON.stringify(sendData),
					url: 'index.php/users/Group/chatRecordAdd'
				}

				// 将当前发送信息 添加到消息列表
				let lastMsg = null;

				if(fileMsg) {
					lastMsg = fileMsg;
				}else {

					let relation_type = ''
					if(this.$refs.inputBar.reply) {
						relation_type = 'reply';
					}else if (this.checkLastTwo(this.previousMsg, value)) {
						relation_type = 'repeat';
					}

					lastMsg = {
						type: contentType,
						content: sendData.data.from.content2,
						send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
						status: 10,
						id: random(1000, 99999),
						avatar: this.imInfo.avatar,
						username: this.imInfo.username,
						from_phone: this.imInfo.phone,
						from_account: this.imInfo.account,
						content_text: value,
						index: this.index,
						success: 'loading',
						uuid: Math.random().toString(36).substring(2, 14),
						relation_id: this.$refs.inputBar.reply ? sendData.relation_id : '',
						relation_type: relation_type,
					}
				}

				if(this.$refs.inputBar.reply) {
					let { content, status, username } = this.$refs.inputBar.currentMsg;
					lastMsg.replyMsg = this.currentMsg;
					lastMsg.replyMsg.html = '';
					lastMsg.replyMsg.from_username = username;
					content.forEach(async(i) => {
						if(i.content != '') {
							lastMsg.replyMsg.html += await this.getQuoteContext(i, status, username);
						}
					});
				}

				if(!fileMsg) {
					this.$refs.paging.addChatRecordData(lastMsg);
				}

				const msg = await chatApi(this.userInfo.token, params);

				if (msg.code === 200) {
					this.$refs.inputBar.currentMsg = null;
					this.$refs.inputBar.reply = false;
					this.$refs.inputBar.replyData = '';

					// ws发送
					sendData.id = msg.data.reId;
					sendData.reId = msg.data.reId;
					sendData.msg_id = msg.data.msgId;
					sendData.groupId = this.group.group_id,
					sendData.need_read_num = msg.data.need_read_num;
					sendData.need_read_id = msg.data.need_read_id;

					// 图片信息处理
					if (contentType == 'img') {
						sendData.data.from.content2.myaccount = this.imInfo.account;
						sendData.data.from.content2.groupId = this.group.group_id;
						lastMsg.content[0].html = await this.setImgUrl(lastMsg.content[0].content);
					}

					lastMsg.need_read_num = msg.data.need_read_num;
					lastMsg.have_read_num = 0;
					lastMsg.have_read_id = '';
					lastMsg.need_read_id = msg.data.need_read_id;
					this.$refs.inputBar.atBlocks = [];
					this.socketStore.send(sendData);
					// 隐藏loading
					this.setSendStatus(lastMsg, 'success', msg.data.msgId, msg.data.reId);
				}else{
					// 隐藏loading
					this.setSendStatus(lastMsg, 'error');
				}
				// 清空内容框中的内容
				this.previousMsg.push(value);
				this.$refs.inputBar.msg = '';
			} catch (error) {
				console.error('发送消息失败:', error);
				// 隐藏loading
				this.setSendStatus(lastMsg, 'error');
				this.$refs.inputBar.msg = '';
			}
			this.copyShow = false;
		},
		setSendStatus(lastMsg, status, msgId, id) {
			const find = this.talkList.find(item => {
				return item.uuid && item.uuid == lastMsg.uuid
			});

			find.success = status;
			if(msgId) {
				find.msg_id = msgId;
				find.id = id;
			}
		},
    // 发送按钮
		handleSendClick () {
			if (!this.$refs.inputBar.msg) {
				return;
			}
			// 发送前将文本信息包裹在P标签中
			this.sendMessage(this.$refs.inputBar.msg, 'text');
			this.$refs.inputBar.msg = '';
		},
    // 打开相机
		chooseCamera () {
			uni.chooseImage({
				count: 1, //默认9
				sizeType: ['original'],
				sourceType: ['camera'],
				success: (res) => {
					res.tempFilePaths.forEach((filePath) => {
						let lastMsg = {
							type: 'img',
							content: [{
								type: 'img',
								content: filePath, // 先用本地路径
								html: { url: filePath, width: 100, height: 100 }, // 临时显示
							}],
							send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
							status: 10,
							id: random(10000, 999999),
							avatar: this.imInfo.avatar,
							username: this.imInfo.username,
							from_phone: this.imInfo.phone,
							from_account: this.imInfo.account,
							percentage: 0,
							uuid: Math.random().toString(36).substring(2, 14),
							success: 'loading',
						}

						this.$refs.paging.addChatRecordData(lastMsg);
						this.uploadImgOrFile(filePath, null, lastMsg);
					});
				}
			});
		},
    // 打开相册
		chooseImage () {
			uni.chooseImage({
				count: 9, //默认9
				sizeType: ['original'],
				sourceType: ['album'],
				success: (res) => {
					res.tempFilePaths.forEach((filePath) => {
						let lastMsg = {
							type: 'img',
							content: [{
								type: 'img',
								content: filePath, // 先用本地路径
								html: { url: filePath, width: 100, height: 100 }, // 临时显示
							}],
							send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
							status: 10,
							id: random(10000, 999989),
							avatar: this.imInfo.avatar,
							username: this.imInfo.username,
							from_phone: this.imInfo.phone,
							from_account: this.imInfo.account,
							percentage: 0,
							uuid: Math.random().toString(36).substring(2, 14),
							success: 'loading',
						}

						this.$refs.paging.addChatRecordData(lastMsg);
						this.uploadImgOrFile(filePath, null, lastMsg);
					});
				}
			});
		},
		beforUpload(e) {
			let lastMsg = {
				type: 'file',
				content: [{
					uploadCompletedNum: 1,
					needUploadNum: 1,
					percentComplete: 100,
					content: '文件',
					icon: setIcon(e.fileName),// 根据后缀处理
					name: e.fileName,
					url: '',
					type: 'file',
					formatSize: formatFileSize(e.fileSize),
					localpath: ''
				}],
				send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
				status: 10,
				id: random(10900, 999999),
				fromavatar: this.imInfo.avatar,
				fromname: this.imInfo.username,
				from_phone: this.imInfo.phone,
				from_account: this.imInfo.account,
				percentage: 0,
				uuid: e.uuid,
				success: 'loading',
			};
			this.$refs.paging.addChatRecordData(lastMsg);
		},
    // 上传 图片 文件
		uploadImgOrFile (filePath, fileInfo,lastMsg = null) {
			const upUrl = `https://chat.mfarmers.com:88/phpApi/public/index.php/users/Index/uploadImg.html?account=${this.imInfo.account}&to_account=${this.group.group_id}&department=${this.imInfo.department}`

			// 文件上传提前推入tasklist 添加上传标志
			if (fileInfo && !lastMsg) {
				lastMsg = {
					type: 'file',
					content: [{
						uploadCompletedNum: 1,
						needUploadNum: 1,
						percentComplete: 100,
						content: '文件',
						icon: setIcon(fileInfo.name), // 根据后缀处理
						name: fileInfo.name,
						url: '',
						type: 'file',
						formatSize: formatFileSize(fileInfo.size),
						localpath: ''
					}],
					send_time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
					status: 10,
					id: random(10000, 999999),
					avatar: this.imInfo.avatar,
					username: this.imInfo.username,
					from_phone: this.imInfo.phone,
					from_account: this.imInfo.account,
					percentage: 0,
					uuid: Math.random().toString(36).substring(2, 14),
					success: 'loading',
				};

				this.$refs.paging.addChatRecordData(lastMsg);
			}
			const uploadTask = uni.uploadFile({
				url: upUrl,
				filePath: filePath,
				name: 'tmp_name',
				success: (uploadFileRes) => {
					const data = JSON.parse(uploadFileRes.data);

					const msgIndex = this.talkList.findIndex(msg =>
							msg.id === lastMsg.id || msg.uuid === lastMsg.uuid
					);
					if (data.data.startsWith("http://chat.mfarmers.com:81")) {
						data.data = data.data.replace("http://chat.mfarmers.com:81/", "https://chat.mfarmers.com:88/");
					}
					// 上传成功 -> 更新 lastMsg
					if (msgIndex !== -1) {
						this.talkList[msgIndex].uploading = false;
						this.talkList[msgIndex].percentage = 100;

						if (fileInfo) {
							this.talkList[msgIndex].content[0].url = data.data;
							this.talkList[msgIndex].fid = data.id;
							this.sendMessage(data.data, 'file', fileInfo, this.talkList[msgIndex]);
						} else {
							this.talkList[msgIndex].content[0].content = data.data;
							this.talkList[msgIndex].content[0].html.url = data.data;
							this.talkList[msgIndex].fid = data.id;
							this.sendMessage(data.data, 'img', null, this.talkList[msgIndex]);
						}
					}
				}
			});

			// H5端监听进度
			// #ifdef H5
			if (fileInfo) {
				this.talkList.push({
					uploadTask: uploadTask,
					uuid: lastMsg.uuid
				})
				uploadTask.onProgressUpdate((res) => {
					this.setProgress(lastMsg.uuid, res.progress);
				});
			}
			// #endif

			uploadTask.onProgressUpdate((res) => {
				const msgIndex = this.talkList.findIndex(msg =>
						msg.id === lastMsg.id || msg.uuid === lastMsg.uuid
				);
				if (msgIndex !== -1) {
					this.talkList[msgIndex].progress = res.progress;
				}
			});
		},
    // 打开聊天设置
		rightClick(){
			this.$nextTick(() => {
				uni.navigateTo({
					url: '/pages/chat/message/group/setting'
				})
			})
		},
		jumpPerson(e) {
			let params = {
				id: e.wid,
				name: e.username,
				type: 'user',
				avatar: e.avatar
			}
			uni.navigateTo({
				url: '/pages/addressBook/details/grdetails',
				animationType: 'none',
				success: function(res) {
					res.eventChannel.emit('details', { item: params })
				}
			});
		}
  }
}
</script>

<style lang="scss">
@import "../config/global.scss";

.chat-container {
	::v-deep .zp-view-super {
		padding-bottom: 10px !important;
	}
}

.mention-popup {
	padding: 12px 0;
}
.mention-header {
	position: relative;
	background-color: #fff;
	padding: 14px 18px 2px 18px;
	display: flex;
	justify-content: center;
	font-size: 16px;
	font-weight: 500;
}
.mention-all {
	margin-top: 14px;
	background-color: #fff;
	padding: 2px 18px;
}
.mention-list {
	display: flex;
	align-items: center;
	margin: 12px 0;
	font-size: 16px;
}
.mention-member {
	margin-top: 14px;
	height: 400px;
}

.related {
	min-width: 40vw;
	padding: 16rpx 28rpx 10rpx 10rpx;
	border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.related-btn {
	display: flex;
}
.related-member {
	background-color: #e3e4e5;
	display: inline-block;
	max-width: 58vw;
	padding: 1px 6px 2px 6px;
	margin: 0 0 4px 6px;
	border-radius: 18rpx;
	font-size: 28rpx;
	color: #555;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	span {
		display: inline-block;
		margin: 0 4rpx;
	}
}
</style>
